#include "stdafx.h"
#include "base/WaitableEvent.h"

namespace xBase
{

    CxWaitableEvent::CxWaitableEvent(BOOL bManualReset, BOOL bInitiallySignaled)
        : m_hEvent(HANDLE(INVALID_HANDLE_VALUE))
    {
        m_hEvent = ::CreateEvent(NULL, bManualReset, bInitiallySignaled, NULL);
    }

    CxWaitableEvent::~CxWaitableEvent(VOID)
    {
        ::CloseHandle(m_hEvent);
    }

    CxWaitableEvent::CxWaitableEvent(HANDLE hEvent)
    {
        m_hEvent = hEvent;
    }

    HANDLE CxWaitableEvent::Release()
    {
        HANDLE hReturn = m_hEvent;
        m_hEvent = HANDLE(INVALID_HANDLE_VALUE);
        return hReturn;
    }

    VOID CxWaitableEvent::Reset()
    {
        ::ResetEvent(m_hEvent);
    }

    VOID CxWaitableEvent::Signal()
    {
        ::SetEvent(m_hEvent);
    }

    BOOL CxWaitableEvent::IsSignaled()
    {
        return Wait(0);
    }

    BOOL CxWaitableEvent::Wait(DWORD dwMilliSecond)
    {
        DWORD dwResult = ::WaitForSingleObject(m_hEvent, dwMilliSecond);

        return dwResult == WAIT_OBJECT_0;
    }

    CxWaitableEvent* CxWaitableEvent::WaitMany(CxWaitableEvent ** ppEvents, UINT nCount)
    {
        if (NULL == ppEvents || 0 == nCount)
        {
            return NULL;
        }

        INT nValidCount = 0;
        CxWaitableEvent*    validEvents[MAXIMUM_WAIT_OBJECTS] = { NULL };
        HANDLE aHandles[MAXIMUM_WAIT_OBJECTS] = { NULL };

        for (UINT i = 0; i < nCount; ++i)
        {
            if(NULL != ppEvents[i])
            {
                validEvents[nValidCount] = ppEvents[i];
                aHandles[nValidCount] = ppEvents[i]->Handle();
                ++nValidCount;
            }
        }

        // The cast is safe because count is small - see the CHECK above.
        DWORD dwResult =
            ::WaitForMultipleObjects(static_cast<DWORD>(nValidCount)
            , aHandles,
            FALSE,      // don't wait for all the objects
            INFINITE);  // no timeout

        if (dwResult >= WAIT_OBJECT_0 + nValidCount) 
        {
            return NULL;
        }

        return validEvents[(dwResult - WAIT_OBJECT_0)];
    }

}